#!/bin/env python
# -*- coding:utf-8 -*-

__author__ = 'iambocai'

import json
import time
import socket
import os
import re
import sys
import commands
import urllib2, base64


class RedisStats:
    # 如果你是自己编译部署到redis，请将下面的值替换为你到redis-cli路径
    _redis_cli = '/usr/local/bin/redis-cli'
    _stat_regex = re.compile(ur'(\w+):([0-9]+\.?[0-9]*)\r')

    def __init__(self, port=7715, passwd='test', host='172.17.80.118'):
        self._cmd = '%s -h %s -p %s info 2>/dev/null' % (self._redis_cli, host, port)
        if passwd not in ['', None]:
            self._cmd = "%s -h %s -p %s -a %s info 2>/dev/null" % (self._redis_cli, host, port, passwd)

    def stats(self):
        ' Return a dict containing redis stats '
        info = commands.getoutput(self._cmd)
        return dict(self._stat_regex.findall(info))


class RedisConfigs_MaxMem:
    # 如果你是自己编译部署到redis，请将下面的值替换为你到redis-cli路径
    _redis_cli = '/usr/local/bin/redis-cli'
    _stat_regex = re.compile(ur'(\w+):([0-9]+\.?[0-9]*)\r')

    def __init__(self, port=7715, passwd='test', host='172.17.80.118'):
        self._cmd = '%s -h %s -p %s config get * 2>/dev/null' % (self._redis_cli, host, port)
        if passwd not in ['', None]:
            self._cmd = "%s -h %s -p %s -a %s CONFIG GET maxmemory 2>/dev/null" % (self._redis_cli, host, port, passwd)

    def configs(self):
        ' Return a dict containing redis maxmemory '
        info = commands.getoutput(self._cmd)
        info = info.splitlines()
        return info[1]


class RedisConfigs_Get:
    # 如果你是自己编译部署到redis，请将下面的值替换为你到redis-cli路径
    _redis_cli = '/usr/local/bin/redis-cli'
    _stat_regex = re.compile(ur'(\w+):([0-9]+\.?[0-9]*)\r')

    def __init__(self, port=7715, passwd='test', host='172.17.80.118', name=None):
        self._cmd = '%s -h %s -p %s  CONFIG GET maxclients 2>/dev/null' % (self._redis_cli, host, port)
        self._name = name
        if passwd not in ['', None]:
            self._cmd = "%s -h %s -p %s -a %s CONFIG GET %s 2>/dev/null" % (self._redis_cli, host, port, passwd, name)

    def configs(self):
        ' Return a dict containing redis maxclients '
        info = commands.getoutput(self._cmd)
        info = info.splitlines()
        return info[1]


class Redis_SlowLen:
    # 如果你是自己编译部署到redis，请将下面的值替换为你到redis-cli路径
    _redis_cli = '/usr/local/bin/redis-cli'

    def __init__(self, port=7715, passwd='test', host='172.17.80.118'):
        self._cmd = '%s -h %s -p %s SLOWLOG len 2>/dev/null' % (self._redis_cli, host, port)
        self._cmdslowlogreset = "%s -h %s -p %s  slowlog reset 2>/dev/null" % (self._redis_cli, host, port)
        self._cmdsmaxlowloglen = "%s -h %s -p %s  slowlog reset 2>/dev/null" % (self._redis_cli, host, port)

        if passwd not in ['', None]:
            self._cmd = "%s -h %s -p %s -a %s SLOWLOG len 2>/dev/null" % (self._redis_cli, host, port, passwd)
            self._cmdslowlogreset = "%s -h %s -p %s -a %s  slowlog reset 2>/dev/null" % (self._redis_cli, host, port, passwd)
            self._cmdsmaxlowloglen = "%s -h %s -p %s -a %s  config get slowlog-max-len 2>/dev/null" % (
            self._redis_cli, host, port, passwd)

    def slowlen(self):
        ' Return slow len  '
        info = commands.getoutput(self._cmd)
        # get max slow len
        slowlogmaxlen = commands.getoutput(self._cmdsmaxlowloglen)
        slowlogmaxlen = slowlogmaxlen.splitlines()
        slowlogmaxlen = slowlogmaxlen[1]
        # if list is full reset it
        if info == slowlogmaxlen:
            slowlogmaxlen = commands.getoutput(self._cmdslowlogreset)
        return info


class Redis_ping:
    # 如果你是自己编译部署到redis，请将下面的值替换为你到redis-cli路径
    _redis_cli = '/usr/local/bin/redis-cli'

    def __init__(self, port=7715, passwd='test', host='172.17.80.118'):
        self._cmd = '%s -h %s -p %s ping 2>/dev/null' % (self._redis_cli, host, port)
        if passwd not in ['', None]:
            self._cmd = "%s -h %s -p %s -a %s ping 2>/dev/null" % (self._redis_cli, host, port, passwd)

    def ping(self):
        ' Return 1 if PONG  '
        info = commands.getoutput(self._cmd)
        if info == 'PONG':
            return 1
        else:
            return 0


class Redis_latency:
    # 如果你是自己编译部署到redis，请将下面的值替换为你到redis-cli路径
    _redis_cli = '/usr/local/bin/redis-cli'

    def __init__(self, port=7715, passwd='test', host='172.17.80.118'):
        self._cmd = '%s -h %s -p %s ping 2>/dev/null' % (self._redis_cli, host, port)
        if passwd not in ['', None]:
            self._cmd = "%s -h %s -p %s -a %s ping 2>/dev/null" % (self._redis_cli, host, port, passwd)

    def latency(self):
        ' Return 1 if PONG  '
        startime = time.time()
        info = commands.getoutput(self._cmd)
        latency = (time.time() - startime) * 1000
        return latency


class Redis_keys:
    # 如果你是自己编译部署到redis，请将下面的值替换为你到redis-cli路径
    _redis_cli = '/usr/local/bin/redis-cli'

    def __init__(self, port=7715, passwd='test', host='172.17.80.118'):
        self._cmd = '%s -h %s -p %s info Keyspace 2>/dev/null' % (self._redis_cli, host, port)
        if passwd not in ['', None]:
            self._cmd = "%s -h %s -p %s -a %s info Keyspace 2>/dev/null" % (self._redis_cli, host, port, passwd)

    def keys(self):
        ' Return 1 if PONG  '
        startime = time.time()
        rs = {}
        info = commands.getoutput(self._cmd).splitlines()
        for key in info:
            if 'keys=' in key:
                result = key.split(':')
                dbs = result[0]
                keys = result[1].split(',')[0]
                keys = keys.split('=')
                value = keys[1]
                rs['keys.' + dbs] = value
        return rs


class Redis_cluster:
    # 如果你是自己编译部署到redis，请将下面的值替换为你到redis-cli路径
    _redis_cli = '/usr/local/bin/redis-cli'

    def __init__(self, port=7715, passwd='test', host='172.17.80.118'):
        self._cmd = '%s -h %s -p %s info Replication 2>/dev/null' % (self._redis_cli, host, port)
        if passwd not in ['', None]:
            self._cmd = "%s -h %s -p %s -a %s info Replication 2>/dev/null" % (self._redis_cli, host, port, passwd)

    def cluster(self):
        ' Return 1 if PONG  '
        startime = time.time()
        rs = -1
        role = ''
        master_link_status = ''
        info = commands.getoutput(self._cmd).splitlines()
        for key in info:
            if 'role:' in key:
                result = key.split(':')
                role = result[1]
            elif 'master_link_status:' in key:
                result = key.split(':')
                master_link_status = result[1]

        if role == 'master' or (role == 'slave' and master_link_status == 'up'):
            return 1
        else:
            return 0

    def get_role(self):
        ' Return 1 if PONG  '
        startime = time.time()
        rs = -1
        role = ''
        info = commands.getoutput(self._cmd).splitlines()
        for key in info:
            if 'role:' in key:
                result = key.split(':')
                role = result[1]

                if role == 'master':
                    return 1
                if role == 'slave':
                    return 0


class Redis_status:
    # 如果你是自己编译部署到redis，请将下面的值替换为你到redis-cli路径
    _redis_cli = '/usr/local/bin/redis-cli'

    def __init__(self, port=7715, passwd='test', host='172.17.80.118'):
        self._cmd = '%s -h %s -p %s cluster info 2>/dev/null' % (self._redis_cli, host, port)
        if passwd not in ['', None]:
            self._cmd = "%s -h %s -p %s -a %s cluster info 2>/dev/null" % (self._redis_cli, host, port, passwd)

    def status(self):
        ' Return 1 if PONG  '
        startime = time.time()
        rs = -1
        cluster_state = ''
        cluster_known_nodes = ''
        info = commands.getoutput(self._cmd).splitlines()
        for key in info:
            if 'cluster_state:' in key:
                result = key.split(':')
                cluster_state = result[1]
            if 'cluster_known_nodes:' in key:
                result = key.split(':')
                cluster_known_nodes = result[1]

        if cluster_state == 'ok':
            # return 1
            cluster_state = 1
            return {'cluster_state': cluster_state, 'cluster_known_nodes': cluster_known_nodes}
        else:
            return 0


def main():
    ip = socket.gethostname()
    timestamp = int(time.time())
    step = 60
    # inst_list中保存了redis配置文件列表，程序将从这些配置中读取port和password，建议使用动态发现的方法获得，如：
    insts_list = [i for i in commands.getoutput("find /etc/redis/ -name '*.conf'").split('\n')]
    # insts_list = [ '/data/redis/conf/redis_7711.conf' ]
    print insts_list
    p = []

    monit_keys = [
        ('connected_clients', 'GAUGE'),
        ('blocked_clients', 'GAUGE'),
        ('instantaneous_ops_per_sec', 'GAUGE'),
        ('used_memory', 'GAUGE'),
        ('used_memory_rss', 'GAUGE'),
        ('mem_fragmentation_ratio', 'GAUGE'),
        ('total_commands_processed', 'COUNTER'),
        ('rejected_connections', 'COUNTER'),
        ('expired_keys', 'COUNTER'),
        ('evicted_keys', 'COUNTER'),
        ('keyspace_hits', 'COUNTER'),
        ('keyspace_misses', 'COUNTER'),
        ('keyspace_hit_ratio', 'GAUGE'),
    ]

    for inst in insts_list:
        port = commands.getoutput("sed -n 's/^port *\([0-9]\{4,5\}\)/\\1/p' %s" % inst)
        passwd = commands.getoutput("sed -n 's/^requirepass *\([^ ]*\)/\\1/p' %s" % inst)
        metric = "redis"
        endpoint = ip
        tags = 'port=%s' % port
        maxmemory = 1
        maxclients = 1
        ping = 1

        # get ping
        try:
            conn = Redis_ping(port, passwd, host=ip)
            ping = conn.ping()
            ping = int(ping)
            i = {
                'Metric': '%s.%s' % ('redis', 'ping'),
                'Endpoint': endpoint,
                'Timestamp': timestamp,
                'Step': step,
                'Value': ping,
                'CounterType': "GAUGE",
                'TAGS': tags
            }
            p.append(i)
        except Exception, e:
            # if ping if fault,check another port
            i = {
                'Metric': '%s.%s' % ('redis', 'ping'),
                'Endpoint': endpoint,
                'Timestamp': timestamp,
                'Step': step,
                'Value': 0,
                'CounterType': "GAUGE",
                'TAGS': tags
            }
            p.append(i)
            continue

        # get cluster

        try:
            conn = Redis_cluster(port, passwd, host=ip)
            cluster = conn.cluster()
            cluster = int(cluster)
            i = {
                'Metric': '%s.%s' % ('redis', 'master_link_status'),
                'Endpoint': endpoint,
                'Timestamp': timestamp,
                'Step': step,
                'Value': cluster,
                'CounterType': "GAUGE",
                'TAGS': tags
            }
            p.append(i)
        except Exception, e:
            pass

        # get cluster role
        try:
            conn = Redis_cluster(port, passwd, host=ip)
            role = conn.get_role()
            role = int(role)
            i = {
                'Metric': '%s.%s' % ('redis', 'role'),
                'Endpoint': endpoint,
                'Timestamp': timestamp,
                'Step': step,
                'Value': role,
                'CounterType': "GAUGE",
                'TAGS': tags
            }
            p.append(i)
        except Exception, e:
            pass

        # get cluster_status
        try:
            conn = Redis_status(port, passwd, host=ip)
            status = conn.status()
            # status = int(status)
            i = {
                'Metric': '%s.%s' % ('redis', 'cluster_status'),
                'Endpoint': endpoint,
                'Timestamp': timestamp,
                'Step': step,
                'Value': status['cluster_state'],
                'CounterType': "GAUGE",
                'TAGS': tags
            }
            p.append(i)
            i = {
                'Metric': '%s.%s' % ('redis', 'cluster_known_nodes'),
                'Endpoint': endpoint,
                'Timestamp': timestamp,
                'Step': step,
                'Value': status['cluster_known_nodes'],
                'CounterType': "GAUGE",
                'TAGS': tags
            }
            p.append(i)
        except Exception, e:
            pass

        # get latency
        try:
            conn = Redis_latency(port, passwd, host=ip)
            latency = conn.latency()
            i = {
                'Metric': '%s.%s' % ('redis', 'latency'),
                'Endpoint': endpoint,
                'Timestamp': timestamp,
                'Step': step,
                'Value': ("%.3f" % latency),
                'CounterType': "GAUGE",
                'TAGS': tags
            }
            p.append(i)
        except Exception, e:
            pass

        try:
            conn = Redis_SlowLen(port, passwd, host=ip)
            slowlen = conn.slowlen()
            i = {
                'Metric': '%s.%s' % ('redis', 'slowlen_value'),
                'Endpoint': endpoint,
                'Timestamp': timestamp,
                'Step': step,
                'Value': int(slowlen),
                'CounterType': "GAUGE",
                'TAGS': tags
            }
            # print i
            p.append(i)
            i = {
                'Metric': '%s.%s' % ('redis', 'slowlen'),
                'Endpoint': endpoint,
                'Timestamp': timestamp,
                'Step': step,
                'Value': int(slowlen),
                'CounterType': "COUNTER",
                'TAGS': tags
            }
            # print i
            p.append(i)
        except Exception, e:
            pass

        try:
            conn = RedisConfigs_MaxMem(port, passwd, host=ip)
            maxmemory = conn.configs()
            maxmemory = int(maxmemory)
        except Exception, e:
            pass
        # get maxclient
        try:
            conn = RedisConfigs_Get(port, passwd, host=ip, name='maxclients')
            maxclients = conn.configs()
            maxclients = int(maxclients)
        except Exception, e:
            pass
        # get dbsize
        try:
            conn = Redis_keys(port, passwd, host=ip)
            rs = conn.keys()
            for key in rs:
                i = {
                    'Metric': '%s.%s' % (metric, key),
                    'Endpoint': endpoint,
                    'Timestamp': timestamp,
                    'Step': step,
                    'Value': int(rs[key]),
                    'CounterType': "GAUGE",
                    'TAGS': tags
                }
                p.append(i)
                i = {
                    'Metric': '%s.%s.speed' % (metric, key),
                    'Endpoint': endpoint,
                    'Timestamp': timestamp,
                    'Step': step,
                    'Value': int(rs[key]),
                    'CounterType': "COUNTER",
                    'TAGS': tags
                }
                p.append(i)
        except Exception, e:
            pass

        try:
            conn = RedisStats(port, passwd, host=ip)
            stats = conn.stats()
        except Exception, e:
            continue

        for key, vtype in monit_keys:
            if key == 'used_memory_rss':
                try:
                    value = int(stats[key])
                    value1 = (float(value) / (maxmemory)) * 100
                    i = {
                        'Metric': '%s.%s.percent' % (metric, key),
                        'Endpoint': endpoint,
                        'Timestamp': timestamp,
                        'Step': step,
                        'Value': ("%.2f" % value1),
                        'CounterType': "GAUGE",
                        'TAGS': tags
                    }
                    p.append(i)
                except:
                    continue
            elif key == 'connected_clients':
                try:
                    value = int(stats[key])
                    value1 = (float(value) / (maxclients)) * 100
                    i = {
                        'Metric': '%s.%s.percent' % (metric, key),
                        'Endpoint': endpoint,
                        'Timestamp': timestamp,
                        'Step': step,
                        'Value': ("%.2f" % value1),
                        'CounterType': "GAUGE",
                        'TAGS': tags
                    }
                    p.append(i)
                except:
                    continue
            elif key == 'keyspace_hit_ratio':
                try:
                    value = float(stats['keyspace_hits']) / (
                                int(stats['keyspace_hits']) + int(stats['keyspace_misses']))
                except ZeroDivisionError:
                    value = 0
            elif key == 'mem_fragmentation_ratio':
                value = float(stats[key])
            else:
                try:
                    value = int(stats[key])
                except:
                    continue
            i = {
                'Metric': '%s.%s' % (metric, key),
                'Endpoint': endpoint,
                'Timestamp': timestamp,
                'Step': step,
                'Value': value,
                'CounterType': vtype,
                'TAGS': tags
            }
            p.append(i)

    print json.dumps(p, sort_keys=True, indent=4)
    method = "POST"
    handler = urllib2.HTTPHandler()
    opener = urllib2.build_opener(handler)
    url = 'http://127.0.0.1:1988/v1/push'
    request = urllib2.Request(url, data=json.dumps(p))
    request.add_header("Content-Type", 'application/json')
    request.get_method = lambda: method
    try:
        connection = opener.open(request)
    except urllib2.HTTPError, e:
        connection = e

    # check. Substitute with appropriate HTTP code.
    if connection.code == 200:
        print connection.read()
    else:
        print '{"err":1,"msg":"%s"}' % connection


if __name__ == '__main__':
    proc = commands.getoutput(' ps -ef|grep %s|grep -v grep|wc -l ' % os.path.basename(sys.argv[0]))
    if int(proc) < 5:
        main()
